home *** CD-ROM | disk | FTP | other *** search
- /*
- * C code from the article
- * "Testing the Convexity of a Polygon"
- * by Peter Schorn and Frederick Fisher,
- * (schorn@inf.ethz.ch, fred@kpc.com)
- * in "Graphics Gems IV", Academic Press, 1994
- */
-
- /* Program to Classify a Polygon's Shape */
-
- #include <stdio.h>
-
- typedef enum { NotConvex, NotConvexDegenerate,
- ConvexDegenerate, ConvexCCW, ConvexCW } PolygonClass;
-
- typedef struct { double x, y; } Point2d;
-
- int WhichSide(p, q, r) /* Given a directed line pq, determine */
- Point2d p, q, r; /* whether qr turns CW or CCW. */
- {
- double result;
- result = (p.x - q.x) * (q.y - r.y) - (p.y - q.y) * (q.x - r.x);
- if (result < 0) return -1; /* q lies to the left (qr turns CW). */
- if (result > 0) return 1; /* q lies to the right (qr turns CCW). */
- return 0; /* q lies on the line from p to r. */
- }
-
- int Compare(p, q) /* Lexicographic comparison of p and q */
- Point2d p, q;
- {
- if (p.x < q.x) return -1; /* p is less than q. */
- if (p.x > q.x) return 1; /* p is greater than q. */
- if (p.y < q.y) return -1; /* p is less than q. */
- if (p.y > q.y) return 1; /* p is greater than q. */
- return 0; /* p is equal to q. */
- }
-
- int GetPoint(f, p) /* Read p's x- and y-coordinate from f */
- FILE *f; /* and return true, iff successful. */
- Point2d *p;
- {
- return !feof(f) && (2 == fscanf(f, "%lf%lf", &(p->x), &(p->y)));
- }
-
- int GetDifferentPoint(f, previous, next)
- FILE *f; /* Read next point into 'next' until it */
- Point2d previous, *next; /* is different from 'previous' and */
- { /* return true iff successful. */
- int eof;
- while((eof = GetPoint(f, next)) && (Compare(previous, *next) == 0));
- return eof;
- }
-
- /* CheckTriple tests three consecutive points for change of direction
- * and for orientation.
- */
- #define CheckTriple \
- if ( (thisDir = Compare(second, third)) == -curDir ) \
- ++dirChanges; \
- curDir = thisDir; \
- if ( thisSign = WhichSide(first, second, third) ) { \
- if ( angleSign == -thisSign ) \
- return NotConvex; \
- angleSign = thisSign; \
- } \
- first = second; second = third;
-
- /* Classify the polygon vertices on file 'f' according to: 'NotConvex' */
- /* 'NotConvexDegenerate', 'ConvexDegenerate', 'ConvexCCW', 'ConvexCW'. */
- PolygonClass ClassifyPolygon(f)
- FILE *f;
- {
- int curDir, thisDir, thisSign, angleSign = 0, dirChanges = 0;
- PolygonClass result;
- Point2d first, second, third, saveFirst, saveSecond;
-
- if ( !GetPoint(f, &first) || !GetDifferentPoint(f, first, &second) )
- return ConvexDegenerate;
- saveFirst = first; saveSecond = second;
- curDir = Compare(first, second);
- while( GetDifferentPoint(f, second, &third) ) {
- CheckTriple;
- }
- /* Must check that end of list continues back to start properly */
- if ( Compare(second, saveFirst) ) {
- third = saveFirst; CheckTriple;
- }
- third = saveSecond; CheckTriple;
-
- if ( dirChanges > 2 ) return angleSign ? NotConvex : NotConvexDegenerate;
- if ( angleSign > 0 ) return ConvexCCW;
- if ( angleSign < 0 ) return ConvexCW;
- return ConvexDegenerate;
- }
-
- int main()
- {
- switch ( ClassifyPolygon(stdin) ) {
- case NotConvex: fprintf( stderr,"Not Convex\n");
- exit(-1); break;
- case NotConvexDegenerate: fprintf( stderr,"Not Convex Degenerate\n");
- exit(-1); break;
- case ConvexDegenerate: fprintf( stderr,"Convex Degenerate\n");
- exit( 0); break;
- case ConvexCCW: fprintf( stderr,"Convex Counter-Clockwise\n");
- exit( 0); break;
- case ConvexCW: fprintf( stderr,"Convex Clockwise\n");
- exit( 0); break;
- }
- }
-